package com.gmlive.common.network.domain;

import android.text.TextUtils;

import androidx.annotation.NonNull;

import com.gmlive.common.network.domain.request.OnDomainRequestCallback;

import java.net.Proxy;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

import okhttp3.Cache;
import okhttp3.Dispatcher;
import okhttp3.OkHttpClient;

/**
 * @Author sven
 * @Date 2020/5/20
 */
public class DomainConfig {
    private static final long REFRESH_INTERVAL = 10 * 60 * 1000L; // 默认更新时间

    /**
     * 请求的ip列表
     */
    List<String> mDomains;

    /**
     * 接口路径
     */
    String mApiPath;

    /**
     * 请求参数
     */
    HashMap<String, String> mParams;

    /**
     * 更新周期
     */
    long mRefreshInterval;

    /**
     * 打印日志
     */
    boolean mLoggable = false;

    /**
     * 开发环境
     */
    boolean mDevelopEnv = false;

    /**
     * 开发环境域名Key前缀，默认为 Test
     */
    String mDevEnvKeyPrefix = "Test";

    OkHttpClient mOkHttpClient = null;

    OnDomainRequestCallback mRequestCallback = null;

    Logger mLogger = null;

    DomainConfig(List<String> domains,
                 String apiPath,
                 HashMap<String, String> params,
                 OkHttpClient client,
                 long refreshInterval,
                 boolean loggable,
                 boolean developEnv,
                 String devEnvKeyPrefix,
                 OnDomainRequestCallback requestCallback,
                 Logger logger) {
        this.mDomains = domains;
        this.mApiPath = apiPath;
        this.mParams = params;
        this.mOkHttpClient = client;
        this.mRefreshInterval = refreshInterval;
        this.mLoggable = loggable;
        this.mDevelopEnv = developEnv;
        this.mDevEnvKeyPrefix = devEnvKeyPrefix;
        this.mRequestCallback = requestCallback;
        this.mLogger = logger;
    }

    public static class Builder {
        private List<String> domains;
        private String apiPath;
        private HashMap<String, String> params;
        private long interval = REFRESH_INTERVAL;
        private boolean loggable = false;
        private boolean developEnv = false;
        private OkHttpClient okHttpClient = null;
        private String devEnvPrefix = "Test";
        private OnDomainRequestCallback callback = null;
        private Logger logger = null;
        private ExecutorService executorService = null;
        private Boolean proxyable = false;

        public Builder() {
        }

        public Builder setDomains(@NonNull String... domainList) {
            domains = Arrays.asList(domainList);
            return this;
        }

        public Builder setDomains(@NonNull List<String> domainSlb) {
            this.domains = domainSlb;
            return this;
        }

        public Builder setApiPath(@NonNull String apiPath) {
            this.apiPath = apiPath;
            return this;
        }

        public Builder addParam(@NonNull String key, @NonNull String value) {
            if (params == null) {
                params = new HashMap<>();
            }

            params.put(key, value);

            return this;
        }

        public Builder setRefreshInterval(long interval) {
            this.interval = interval;
            return this;
        }

        public Builder setLoggable(boolean loggable) {
            this.loggable = loggable;
            return this;
        }

        public Builder setDevelopEnv(boolean developEnv) {
            this.developEnv = developEnv;
            return this;
        }

        public Builder setDevelopPrefix(String prefix) {
            devEnvPrefix = prefix;
            return this;
        }

        public Builder setOkHttpClient(OkHttpClient client) {
            okHttpClient = client;
            return this;
        }

        public Builder setRequestCallback(OnDomainRequestCallback requestCallback) {
            this.callback = requestCallback;
            return this;
        }

        public Builder setLogger(Logger logger) {
            this.logger = logger;
            return this;
        }

        public Builder setOkHttpExecutorService(ExecutorService executorService) {
            this.executorService = executorService;
            return this;
        }

        public Builder setProxyable(boolean proxyable) {
            this.proxyable = proxyable;
            return this;
        }

        public DomainConfig build() {
            if (domains.isEmpty()) {
                throw new IllegalArgumentException("获取动态域名的 IP 列表不能为空！");
            }

            if (TextUtils.isEmpty(apiPath)) {
                throw new IllegalArgumentException("请求的 url 路径不能为空！");
            }

            if (params == null || params.isEmpty()) {
                throw new IllegalArgumentException("请求的 参数 不能为空！");
            }

            if (okHttpClient == null) {
                okHttpClient = getDefaultOkHttpClient(executorService, proxyable);
            }

            if (logger == null) {
                logger = EMPTY;
            }

            return new DomainConfig(domains, apiPath, params, okHttpClient, interval, loggable,
                    developEnv, devEnvPrefix, callback, logger);
        }
    }

    private static final Logger EMPTY = new Logger() {
        @Override
        public void log(String message) {
        }
    };

    public interface Logger {
        void log(String message);
    }

    private static OkHttpClient getDefaultOkHttpClient(ExecutorService executorService, Boolean proxyable) {
        OkHttpClient.Builder builder = new OkHttpClient.Builder()
                .callTimeout(5, TimeUnit.SECONDS)
                .connectTimeout(5, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5, TimeUnit.SECONDS)
                .retryOnConnectionFailure(false)
                .sslSocketFactory(DefaultSSLFactory.sslContext.getSocketFactory(), DefaultSSLFactory.xtm)
                .hostnameVerifier(DefaultSSLFactory.DO_NOT_VERIFY)
                .eventListenerFactory(new OkHttpEventListenerFactory());
        if (executorService != null) {
            builder.dispatcher(new Dispatcher(executorService));
        }
        if (!proxyable) {
            builder.proxy(Proxy.NO_PROXY);
        }
        return builder.build();
    }
}
